import { get } from '@/utils/lodashExt';
import { isNullOrUnDef } from '../is';
import type { Feature } from './feature';

/**
 * @class FilterUtil
 */
class FilterUtil {
  static nestingOperators = ['&&', '||', '!'];

  static handleNestedFilter = (filter: Array<any>, properties: any): boolean => {
    switch (filter[0]) {
      case '&&':
        let intermediate = true;
        let restFilter = filter.slice(1);
        restFilter.forEach((f: any) => {
          if (!FilterUtil.whereMatchesFilter(f, properties)) {
            intermediate = false;
          }
        });
        return intermediate;
      case '||':
        intermediate = false;
        restFilter = filter.slice(1);
        restFilter.forEach((f: any) => {
          if (FilterUtil.whereMatchesFilter(f, properties)) {
            intermediate = true;
          }
        });
        return intermediate;
      case '!':
        return !FilterUtil.whereMatchesFilter(filter[1], properties);
      default:
        throw new Error('Cannot parse Filter. Unknown combination or negation operator.');
    }
  };

  static handleSimpleFilter = (filter: Array<any>, properties: any): boolean => {
    const propName = filter[1];
    const featureValue = get(properties, propName);
    let filterValue = filter[2];
    switch (filter[0]) {
      case '==':
        return '' + featureValue === '' + filterValue;
      case '*=':
        filterValue = filterValue as string;
        if (featureValue && filterValue.length > featureValue.length) {
          return false;
        } else if (featureValue) {
          return featureValue.indexOf(filterValue) !== -1;
        } else {
          return false;
        }
      case '!=':
        return '' + featureValue !== '' + filterValue;
      case '<':
        return parseFloat(featureValue) < Number(filterValue);
      case '<=':
        return parseFloat(featureValue) <= Number(filterValue);
      case '>':
        return parseFloat(featureValue) > Number(filterValue);
      case '>=':
        return parseFloat(featureValue) >= Number(filterValue);
      default:
        throw new Error('Cannot parse Filter. Unknown comparison operator.');
    }
  };

  static whereMatchesFilter = (filter: Array<any>, properties: any): boolean => {
    const firstWhere = filter[0] as any;
    let matchesFilter = true;
    if (FilterUtil.nestingOperators.includes(firstWhere)) {
      matchesFilter = FilterUtil.handleNestedFilter(filter, properties);
    } else {
      matchesFilter = FilterUtil.handleSimpleFilter(filter, properties);
    }
    return matchesFilter;
  };

  static featureMatchesFilter = (feature: Feature, properties: any): boolean => {
    if (isNullOrUnDef(feature)) {
      //无条件匹配全部
      return true;
    }
    if (!Array.isArray(feature.whereFilter)) {
      //无条件匹配全部
      return true;
    }
    if (feature.whereFilter.length === 0) {
      //无条件匹配全部
      return true;
    }
    return FilterUtil.whereMatchesFilter(feature.whereFilter, properties);
  };

  static getMatches = (features: Feature[], properties:any): Feature | undefined => {
    const fs = features.filter((feature) => {
      return FilterUtil.featureMatchesFilter(feature, properties);
    });
    const f = fs[0];
    return f;
  };
}

export default FilterUtil;
